package vg.modules.graph_comparison.components;

import vg.services.graph_view_manager.interfaces.graph_comparison.AGraphComparisonView;
import vg.services.graph_view_manager.interfaces.graph_comparison.InputGraphComparisonAlgorithmProperties;
import vg.services.main_manager.MainManager;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.*;

/**
 * Attribute weight table dialog.
 * @author Timur Zolotuhin (tzolotuhin@gmail.com)
 */
public class AttrWeightTableDialog {
    // Mutex
    private static final Object generalMutex = new Object();

    public static void show(final AGraphComparisonView graphComparisonView) {
        if (!SwingUtilities.isEventDispatchThread()) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    synchronized (generalMutex) {
                        show(graphComparisonView);
                    }
                }
            });
        } else {
            synchronized (generalMutex) {
                // create components
                if (graphComparisonView == null)
                    return;

                // get current input properties for the graph comparison
                InputGraphComparisonAlgorithmProperties input = graphComparisonView.getCurrentInputGraphComparisonAlgorithmProperties();

                // initialize vertexAttr and edgeAttr
                Map<String, Float> vertexAttr = input.getVertexAttributeAndWeightTable();
                if (vertexAttr == null)
                    vertexAttr = Collections.emptyMap();

                Map<String, Float> edgeAttr = input.getEdgeAttributeAndWeightTable();
                if (edgeAttr == null)
                    edgeAttr = Collections.emptyMap();

                int vertexAttrSize = vertexAttr.size();
                int edgeAttrSize = edgeAttr.size();

                // initialize draw components for dialog
                JComponent[] dialogComponents = new JComponent[vertexAttrSize + edgeAttrSize + 2];
                Queue<AttrImportanceView> vertexAttrImportanceView = new ArrayDeque<AttrImportanceView>();
                Queue<AttrImportanceView> edgeAttrImportanceView = new ArrayDeque<AttrImportanceView>();
                int dialogComponentIndex = 0;

                dialogComponents[dialogComponentIndex++] = new JLabel("Vertex attributes");

                if (vertexAttrSize > 0) {
                    for (String attrName : vertexAttr.keySet()) {
                        AttrImportanceView e = new AttrImportanceView(attrName, vertexAttr.get(attrName));
                        vertexAttrImportanceView.add(e);
                        dialogComponents[dialogComponentIndex++] = e.getView();
                    }
                }

                dialogComponents[dialogComponentIndex++] = new JLabel("Edge attributes");

                if (edgeAttrSize > 0) {
                    for (String attrName : edgeAttr.keySet()) {
                        AttrImportanceView e = new AttrImportanceView(attrName, edgeAttr.get(attrName));
                        edgeAttrImportanceView.add(e);
                        dialogComponents[dialogComponentIndex++] = e.getView();
                    }
                }

                // show dialog
                if (JOptionPane.showConfirmDialog(MainManager.view.getMainFrame(), dialogComponents, "Conveyor settings", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) {
                    LinkedHashMap<String, Float> newVertexAttrTable = new LinkedHashMap<String, Float>(vertexAttrSize);
                    LinkedHashMap<String, Float> newEdgeAttrTable = new LinkedHashMap<String, Float>(edgeAttrSize);

                    for (AttrImportanceView buf : vertexAttrImportanceView) {
                        newVertexAttrTable.put(buf.getName(), buf.getValue());
                    }

                    for (AttrImportanceView buf : edgeAttrImportanceView) {
                        newEdgeAttrTable.put(buf.getName(), buf.getValue());
                    }

                    // set new input properties
                    input.setVertexAttributeAndWeightTable(newVertexAttrTable);
                    input.setEdgeAttributeAndWeightTable(newEdgeAttrTable);
                    graphComparisonView.setInputGraphComparisonAlgorithmProperties(input);
                }
            }
        }
    }

    private static class AttrImportanceView {
        private JPanel view;
        private String barrierViewName;
        private Float barrierViewValue;

        private AttrImportanceView(String name, Float value) {
            this.barrierViewName = name;
            this.barrierViewValue = value;

            final JLabel nameLabel = new JLabel(name);

            final JSlider valueSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, (int)(value * 100));
            valueSlider.setMajorTickSpacing(10);
            valueSlider.setMinorTickSpacing(2);
            valueSlider.setPaintTicks(true);
            valueSlider.setPaintLabels(true);

            view = new JPanel(new GridBagLayout());

            view.add(nameLabel, new GridBagConstraints(0,0,  1,1,  1,1,  GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5),  0,0));
            view.add(valueSlider, new GridBagConstraints(1,0,  1,1,  1,1,  GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5),  150, 0));

            view.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));

            valueSlider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    int newValue = valueSlider.getValue();
                    barrierViewValue = newValue * 0.01f;
                }
            });
        }

        public JComponent getView() {
            return view;
        }

        public String getName() {
            return barrierViewName;
        }

        public Float getValue() {
            return barrierViewValue;
        }
    }
}
